//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
namespace LargoCommon.Music
{
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
///
/// Harmonic Stream Analyzer.
///
public class HarmonicStreamAnalyzer {
#region Fields
///
/// Maximum number of Tones In Chord.
///
private readonly byte maxTonesInChord;
///
/// Full Harmonization.
///
private readonly bool fullHarmonization;
///
/// The header
///
private readonly MusicalHeader header;
///
/// Last harmonic structure.
///
private HarmonicStructure lastHarmonicStructure;
///
/// The first tick.
///
private byte firstTick;
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
/// The given header.
/// The given max tones in chord.
/// If set to true [given full harmonization].
public HarmonicStreamAnalyzer(MusicalHeader givenHeader, byte givenMaxTonesInChord, bool givenFullHarmonization) {
this.header = givenHeader;
this.maxTonesInChord = givenMaxTonesInChord;
this.fullHarmonization = givenFullHarmonization;
}
#endregion
#region Properties
///
/// Gets or sets Harmonic Space.
///
public HarmonicSpace HarmonicSpace { get; set; }
///
/// Gets or sets a value indicating whether Sharp Chord Edges.
///
public bool SharpChordEdges { get; set; }
#endregion
#region String representation
/// String representation of the object.
/// Returns value.
public override string ToString() {
return $"HarmonicStreamAnalyzer (SharpChordEdges {this.SharpChordEdges})";
}
#endregion
#region Public methods
///
/// Determine Harmony In Bar.
///
/// The given bar.
///
/// Returns value.
///
public HarmonicBar DetermineHarmonyInBar(MusicalBar givenBar) {
var sourceTones = givenBar.MelodicTonesAround(6, 6);
var harmonicModality = new HarmonicModality(this.header.System.HarmonicOrder, sourceTones, 0, false);
var barTones = givenBar.MelodicTones;
if (barTones == null) {
return null;
}
HarmonicBar harmonicBar;
var musicalTones = barTones;
if (!musicalTones.Any()) {
harmonicBar = HarmonicBar.EmptyBar(this.header.System.HarmonicOrder, this.header.System.RhythmicOrder);
harmonicBar.BarNumber = 1; //// 2016/08 givenBar.BarNumber; //// 2016/08 ?!
return harmonicBar;
}
var rsystem = this.header.System.RhythmicSystem;
var rorder = this.header.System.RhythmicOrder;
var barMetric = new BinaryStructure(rsystem, 0);
//// barMetric.On(0);
harmonicBar = new HarmonicBar(0, givenBar.BarNumber) { Header = givenBar.Body.Context.Header };
this.lastHarmonicStructure = null;
//// int length;
this.firstTick = 0;
this.HarmonicSpace.Reset(harmonicModality);
for (byte tick = 0; tick < rorder; tick++) {
var br = new BitRange(rorder, tick, 1);
var tonesAtTick = new MusicalToneCollection(musicalTones, br, false);
this.AnalyzeHarmonyAtTick(harmonicBar, tick, tonesAtTick, barMetric);
}
if (this.firstTick < this.header.System.RhythmicOrder) {
var harmonicStructure = this.HarmonicSpace.DetermineHarmonicStructure(this.maxTonesInChord, this.fullHarmonization);
if (harmonicStructure != null) {
this.ResolveStructure(harmonicBar, barMetric, harmonicStructure, this.header.System.RhythmicOrder);
}
}
barMetric.DetermineLevel();
var barMetricCode = barMetric.GetStructuralCode;
harmonicBar.SetBarMetricCode(barMetricCode);
harmonicBar.SetHarmonicModalityCode(harmonicModality.GetStructuralCode);
return harmonicBar;
}
#endregion
#region Public methods
///
/// Analyzes the harmony at tick.
///
/// The harmonic motive bar.
/// The tick.
/// The melodic tones.
/// The bar metric.
private void AnalyzeHarmonyAtTick(HarmonicBar harmonicBar, byte givenTick, ICollection givenTones, BinaryStructure barMetric) {
Contract.Requires(givenTones != null);
var tick = givenTick;
var anyStartAtThisTick = givenTones.Count > 0 && (from dt in givenTones
where dt.BitFrom == tick
select 1).Any();
if (anyStartAtThisTick && tick > 0) {
var harmonicStructure = this.HarmonicSpace.DetermineHarmonicStructure(this.maxTonesInChord, this.fullHarmonization);
if (harmonicStructure != null) {
//// var harSystem = harmonicStructure.HarmonicSystem; //// HarmonicSystem.GetHarmonicSystem(this.SysOrder);
//// var modality = new HarmonicModality(harSystem, 1387);
////201508 harmonicStructure = DataLink.BridgeHarmony.CompleteHarmonicStructure(harSystem, modality, harmonicStructure.GetStructuralCode());
//// harmonicStructure.DetermineBehavior();
this.ResolveStructure(harmonicBar, barMetric, harmonicStructure, tick);
this.firstTick = tick;
if (this.SharpChordEdges) {
this.HarmonicSpace.Forget();
//// this.HarmonicSpace.Reset(harmonicModality);
}
}
}
else {
barMetric.Off(tick);
}
if (givenTones.Count > 0) {
this.HarmonicSpace.AcceptTonesOfTheTick(givenTones);
}
}
///
/// Resolves the structure.
///
/// The harmonic motive bar.
/// The bar metric.
/// The harmonic structure.
/// The given tick.
private void ResolveStructure(HarmonicBar harmonicBar, BinaryStructure barMetric, HarmonicStructure harmonicStructure, byte tick) {
Contract.Requires(barMetric != null);
Contract.Requires(harmonicStructure != null);
var extendPrevious = (this.lastHarmonicStructure != null) && (string.CompareOrdinal(harmonicStructure.ElementSchema, this.lastHarmonicStructure.ElementSchema) == 0);
if (extendPrevious) {
barMetric.Off(this.firstTick);
this.lastHarmonicStructure.Length = (byte)(this.lastHarmonicStructure.Length + tick - this.firstTick);
}
else {
barMetric.On(this.firstTick);
harmonicStructure.BitFrom = this.firstTick;
var length = tick - this.firstTick;
harmonicStructure.Length = (byte)length;
harmonicBar.AddStructure(harmonicStructure);
this.lastHarmonicStructure = harmonicStructure;
}
}
#endregion
}
}